package com.five.matebook.activity.db;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;

import com.five.matebook.activity.config.StroageConfig;
import com.five.matebook.activity.outcome.OutcomeColume;
import com.five.matebook.utils.DateUtils;
import com.five.matebook.utils.LogUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class TableBase {
    private Context context;
    protected String mTableName;
    private String mTag;

    protected TableBase(Context context, String tableName) {
        this.context = context;
        this.mTableName = tableName;
        this.mTag = TableBase.class.getSimpleName() + "-" + tableName;
    }

    private String getSqlType(Class cls, int maxStrLen) {
        if (cls.equals(Integer.class) || cls.equals(Long.class)) {
            return "INTEGER";
        } else if (cls.equals(Float.class)) {
            return "FLOAT";
        }
        return String.format("varchar(%d)", maxStrLen);
    }

    public void addColume(String columeName, Class type, int maxLen) {
        if (TextUtils.isEmpty(columeName) || maxLen <= 0 || maxLen > 1000) {
            LogUtils.d(mTag, "addColume() failed!");
            return;
        }
        String sqlType = getSqlType(type, maxLen);
        String sql = String.format("ALTER TABLE %s ADD COLUMN %s %s;", mTableName, columeName, sqlType);
        try {
            DbHelper.getInstance(context).getDb().execSQL(sql);
        } catch (Exception e) {
        }
    }

    public void createIfNotExist() {
        String sql = "create table IF NOT EXISTS " + mTableName + "(id integer primary key autoincrement)";
        DbHelper.getInstance(context).getDb().execSQL(sql);
    }

    private static final String COLUME_UPDATE_TIME = "updateTime";
    private static final String COLUME_ID = COLUME_UPDATE_TIME;

    private long setUpdateTime(ContentValues contentValues) {
        long updateTime;
        do {
            updateTime = DateUtils.getNowTimeLong();

            List<Map<String, Object>> ret = queryById(updateTime);
            if (ret.size() == 0) {
                break;
            }
        } while (true);
        {
            // 添加创建/更新时间
            contentValues.put(OutcomeColume.UPDATE_TIME, updateTime);
        }
        return updateTime;
    }

    /**
     * 添加一条新的记录
     *
     * @param data
     * @return 记录的唯一id，后续update需要指定该id
     */
    public OneQueryData add(Map<String, Object> data) {
        if (data == null) {
            return null;
        }
        ContentValues values = new ContentValues();
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            if ("id".equals(entry.getKey())) {
                continue;
            }
            Object obj = entry.getValue();
            if (obj instanceof Long) {
                values.put(entry.getKey(), (Long) obj);
            } else if (obj instanceof Integer) {
                values.put(entry.getKey(), (Long) obj);
            } else {
                values.put(entry.getKey(), String.valueOf(obj));
            }
        }

        long updateTime = setUpdateTime(values);

        DbHelper.getInstance(context).getDb().insert(mTableName, null, values);
        QueryFilter filter = new QueryFilter.Builder()
                .addLongRange(COLUME_UPDATE_TIME, updateTime, updateTime)
                .build();

        StroageConfig.get(context).setHasUpdate(true);

        return this.query(filter).get(0);
    }

    @SuppressLint("Range")
    public List<Map<String, Object>> queryById(long id) {
        List<Map<String, Object>> ret = new ArrayList<>();
        Cursor cursor = DbHelper.getInstance(context).getDb().query(mTableName, new String[]{"*"},
                String.format("%s = ?", COLUME_ID),
                new String[]{String.valueOf(id)}, null, null, null);
        while (cursor.moveToNext()) {
            Map<String, Object> oneData = new HashMap<>();
            for (String colume : cursor.getColumnNames()) {
                oneData.put(colume, cursor.getString(cursor.getColumnIndex(colume)));
            }
            ret.add(oneData);
        }
        return ret;
    }

    @SuppressLint("Range")
    public List<OneQueryData> query(QueryFilter filter) {
        if (filter == null) {
            return null;
        }
        List<OneQueryData> ret = new ArrayList<>();
        try {
            Cursor cursor = DbHelper.getInstance(context).getDb().query(mTableName, new String[]{filter.getOutputColume()},
                    filter.getSelection(),
                    filter.getSelectionArgs(), null, null, filter.getOrderBy(), filter.getLimit());
            while (cursor.moveToNext()) {
                Map<String, Object> oneData = new HashMap<>();
                for (String colume : cursor.getColumnNames()) {
                    oneData.put(colume, cursor.getString(cursor.getColumnIndex(colume)));
                }
                ret.add(new OneQueryData(oneData));
            }
        } catch (Exception e) {}
        return ret;
    }

    @SuppressLint("Range")
    public List<OneQueryData> queryByHanppenTime(long hanppenTimeBegin, long hanppenTimeEnd) {
        List<OneQueryData> ret = new ArrayList<>();
        final String coulume = OutcomeColume.HAPPEND_TIME;
        Cursor cursor = DbHelper.getInstance(context).getDb().query(mTableName, new String[]{"*"},
                String.format("%s >= ? and %s <= ?", coulume, coulume),
                new String[]{String.valueOf(hanppenTimeBegin), String.valueOf(hanppenTimeEnd)}, null, null, String.format("%s DESC", coulume));
        while (cursor.moveToNext()) {
            Map<String, Object> oneData = new HashMap<>();
            for (String colume : cursor.getColumnNames()) {
                oneData.put(colume, cursor.getString(cursor.getColumnIndex(colume)));
            }
            ret.add(new OneQueryData(oneData));
        }
        return ret;
    }

    public OneQueryData update(long id, Map<String, Object> data) {
        if (data == null) {
            return null;
        }
        ContentValues values = new ContentValues();
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            if ("id".equals(entry.getKey())) {
                continue;
            }
            Object obj = entry.getValue();
            if (obj instanceof Long) {
                values.put(entry.getKey(), (Long) obj);
            } else if (obj instanceof Integer) {
                values.put(entry.getKey(), (Long) obj);
            } else {
                values.put(entry.getKey(), String.valueOf(obj));
            }
        }

        long updateTime = setUpdateTime(values);

        DbHelper.getInstance(context).getDb().update(mTableName, values, "id = ?", new String[]{String.valueOf(id)});

        StroageConfig.get(context).setHasUpdate(true);

        QueryFilter filter = new QueryFilter.Builder()
                .addLongRange("id", id, id)
                .build();
        return this.query(filter).get(0);
    }
}
